#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
	// <programme> ::= debut <seq_inst> fin FIN_FICHIER

	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
	// <seqInst> ::= <inst> ; { <inst> ; }

	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		si->ajouteInstruction(inst());
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour() == "si" || ls.getSymCour() == "tantque" || ls.getSymCour() == "repeter" || ls.getSymCour() == "lire" || ls.getSymCour()=="pour" || ls.getSymCour()=="ecrire");
	// tant que le symbole courant est un debut possible d'instruction...
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
// <inst> ::= <affectation> | <inst_condi>
        if (ls.getSymCour()=="<VARIABLE>")
                return affectation();
        else if (ls.getSymCour()=="si") // on lance la "conditionr qui contiendra elle-meme des instructions. (condition = ExpBool)
                return instSi();
//        else if (ls.getSymCour()=="tantque") // idem que if
//                return instTq();
//        else if (ls.getSymCour()=="repeter") // idem que if
//                return instRepeter();        
//        else if (ls.getSymCour()=="lire") // idem que if
//                return instLire();
//        else if (ls.getSymCour()=="pour") // idem que if
//                return instPour();        
//        else if (ls.getSymCour()=="ecrire") // idem que if
//                return instEcrire();
        else{
        erreur("<inst>");
        return NULL;
        }
	
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>

	testerSymCour("<VARIABLE>");
        ls.suivant();
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	sauterSymCour("=");
	Noeud* exp = expression();
	return new NoeudAffectation(var,exp);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <facteur> { <opBinaire> <facteur> }

	Noeud* term = terme();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-" || ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		Symbole operateurAdd = opBinaire(); // on stocke le symbole de l'opérateur
		Noeud* termDroit=terme(); // lecture de l'operande droit
		term = new NoeudOperateurBinaire(operateurAdd,term,termDroit); // const. du noeud
	}
	return term;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

	Noeud* fact=NULL;

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>"|| ls.getSymCour()=="<CHAINE>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-") {
		ls.suivant();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		fact=expBool();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
	return fact;
}

////////////////////////////////////////////////////////////////////////////////

Noeud* LecteurPhraseAvecArbre::terme(){
// <terme> ::= <facteur> { <opMult> <facteur> }
        Noeud* fact=facteur();

   while (ls.getSymCour()=="*" || ls.getSymCour()=="/") {
                Symbole operateur =opBinaire(); 
                Noeud* factDroit=facteur(); // lecture de l'operande droit
                fact = new NoeudOperateurBinaire(operateur,fact,factDroit); // const. du noeud

        }
        return fact;
}   

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBinaire() {
// <opBinaire> ::= + | - | *  | /
	Symbole operateur;
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" || ls.getSymCour()=="*" || ls.getSymCour()=="/" || ls.getSymCour()=="et" || ls.getSymCour()=="ou" || ls.getSymCour()=="==" || ls.getSymCour()=="!=" || ls.getSymCour()=="<" || ls.getSymCour()=="<=" || ls.getSymCour()==">" || ls.getSymCour()==">=") {
		operateur=ls.getSymCour();
		ls.suivant();
	}
	else
		erreur("<opBinaire>");
	return operateur;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation()
// <relation> ::= <expBool> { <opRel> <expBool> }
// <expression> { <opRel> <expression> }
{
        Noeud* exp = expression();

        while (ls.getSymCour()=="==" || ls.getSymCour()=="!=" ||
                        ls.getSymCour()=="<" || ls.getSymCour()=="<=" ||
                        ls.getSymCour()==">" || ls.getSymCour()==">=") {
        //      opRel();
        //      expression();
                Symbole operateur = opBinaire();
                Noeud* expDroit = expression();
                exp = new NoeudOperateurBinaire(operateur,exp,expDroit); // const. du noeud
        }
        return exp;
}

///////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBool() {
    // <expBoolEt> ::= <relation> { <opBoolEt> <relation> }
    Noeud* r = relation();
    while (ls.getSymCour() == "et" || ls.getSymCour() == "ou") {
        r = new NoeudOperateurBinaire(opBinaire(), r, relation());
    }
    return r;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSi(){
//  <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> }
//  [ sinon <seqInst> ] finsi
        Noeud* exp=NULL;
        Noeud* suivant=NULL;
        Noeud* si=NULL;
        Noeud* seqinst=NULL;
        
        if (ls.getSymCour()=="si") {

                sauterSymCour("si");
                sauterSymCour("(");
                exp = expBool();
                sauterSymCour(")");
                seqinst = seqInst();
                suivant = instSi();
                sauterSymCour("finsi");
                si = new NoeudSi(exp,seqinst, suivant);
        }
        else if (ls.getSymCour()=="sinonsi") {

                sauterSymCour("sinonsi");
                sauterSymCour("(");
                exp = expBool();
                sauterSymCour(")");
                seqinst = seqInst();
                suivant = instSi();
                si = new NoeudSi(exp,seqinst, suivant);
                
        }
        else if (ls.getSymCour()=="sinon") {
               
                sauterSymCour("sinon");
               // ls.suivant();
                seqinst = seqInst();
                exp = ts.chercheAjoute(Symbole("1"));
                si = new NoeudSi(exp,seqinst,suivant);
               
                
        } 
        
        return si;
}



////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
